﻿Imports ESRI.ArcGIS.Display
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.Geometry

Public Class SymbolToImage
    Private Shared image_dpi As Integer = 0
    Private Shared Sub getImageDPI()
        If image_dpi < 1 Then
            Dim b As New Bitmap(1, 1)
            Dim g As Graphics = Graphics.FromImage(b)
            image_dpi = g.DpiY
            b.Dispose()
            ' g.ReleaseHdc()
            g.Dispose()
        End If
    End Sub
    Public Shared Function GetImageFromSymbol(ByVal symbol As ISymbol) As Bitmap
        Dim scale As Integer = 4
        Dim bitmap As Bitmap = GetImageFromSymbolByScale(symbol, scale)
        Dim newBitmap As Bitmap = scaleImage(bitmap, scale)
        bitmap.Dispose()
        bitmap = Nothing
        Return newBitmap
    End Function
    Private Shared Function GetImageFromSymbolByScale(ByVal symbol As ISymbol,
                                              Optional ByVal scale As Integer = 1) As Bitmap
        getImageDPI()
        Dim width As Integer = 0
        Dim height As Integer = 0
        If TypeOf symbol Is IMarkerSymbol Then
            Dim size As Double = CType(symbol, IMarkerSymbol).Size
            width = size * image_dpi / 72 + 2
            height = width
        Else
            width = 64
            height = 64
        End If
        width = width * scale
        height = height * scale
        Dim bitmap = New Bitmap(width, height)
        Dim graphic As Graphics = Graphics.FromImage(bitmap)
        Dim dpi As Double = graphic.DpiY * scale
        Dim envelope As IEnvelope = New EnvelopeClass()
        envelope.PutCoords(0, 0, width, height)
        Dim geometry As IGeometry = GetSymbolGeometry(symbol, envelope)
        Dim myRect = New tagRECT()
        myRect.bottom = bitmap.Height
        myRect.left = 0
        myRect.right = bitmap.Width
        myRect.top = 0
        Dim displayTransformation As IDisplayTransformation = New DisplayTransformationClass()
        displayTransformation.VisibleBounds = envelope
        displayTransformation.Bounds = envelope
        displayTransformation.DeviceFrame = myRect
        displayTransformation.Resolution = dpi
        Dim hdc As IntPtr = graphic.GetHdc()
        symbol.SetupDC(hdc.ToInt32(), displayTransformation)
        symbol.Draw(geometry)
        symbol.ResetDC()
        graphic.ReleaseHdc(hdc)
        graphic.Dispose()
        Return bitmap
    End Function
    Private Shared Function scaleImage(oribitmap As Bitmap, scale As Double) As Bitmap
        Dim width As Integer = oribitmap.Width / scale
        Dim height As Integer = oribitmap.Height / scale
        Dim bitmap = New Bitmap(width, height)
        Dim graphic As Graphics = Graphics.FromImage(bitmap)
        graphic.InterpolationMode = Drawing2D.InterpolationMode.High
        graphic.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
        graphic.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
        graphic.DrawImage(
            oribitmap,
            New System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
            New System.Drawing.Rectangle(0, 0, oribitmap.Width, oribitmap.Height),
            System.Drawing.GraphicsUnit.Pixel)
        graphic.Dispose()
        Return bitmap
    End Function
    Private Shared Function GetSymbolGeometry(ByVal symbol As ISymbol, ByVal envelop As IEnvelope) As IGeometry
        Dim geometry As IGeometry = Nothing
        If TypeOf symbol Is IMarkerSymbol Then
            Dim area = CType(envelop, IArea)
            geometry = area.Centroid
        ElseIf TypeOf symbol Is ILineSymbol Then
            Dim polyline As IPolyline = New PolylineClass()
            Dim pointCollection = CType(polyline, IPointCollection)
            Dim point As IPoint = New PointClass()
            Dim before As Object = Type.Missing
            Dim after As Object = Type.Missing
            point.PutCoords(envelop.XMin, envelop.YMax)
            pointCollection.AddPoint(point, before, after)
            point.PutCoords((envelop.XMax - envelop.XMin) / 3, envelop.YMin)
            pointCollection.AddPoint(point, before, after)
            point.PutCoords((envelop.XMax - envelop.XMin) * 2 / 3, envelop.YMax)
            pointCollection.AddPoint(point, before, after)
            point.PutCoords((envelop.XMax - envelop.XMin), envelop.YMin)
            pointCollection.AddPoint(point, before, after)
            geometry = polyline
        ElseIf TypeOf symbol Is IFillSymbol Then
            geometry = envelop
        ElseIf TypeOf symbol Is ITextSymbol Then
            Dim area = CType(envelop, IArea)
            geometry = area.Centroid
        End If
        Return geometry
    End Function
End Class
